﻿using MvCamCtrl.NET;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;

using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static MvCamCtrl.NET.MyCamera;
using static System.Net.Mime.MediaTypeNames;
using Color = System.Drawing.Color;

#pragma warning disable CA2200

// ReSharper disable PossibleIntendedRethrow

// ReSharper disable ConditionIsAlwaysTrueOrFalse
// ReSharper disable RedundantDefaultMemberInitializer
#pragma warning disable CS0414 // Field is assigned but its value is never used
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS0652 // Comparison to integral constant is useless; the constant is outside the range of the type
#pragma warning disable IDE0049
#pragma warning disable IDE0049
#pragma warning disable CS8603 // Possible null reference return.

// ReSharper disable MemberCanBeMadeStatic.Local
// ReSharper disable IdentifierTypo
// ReSharper disable RedundantAssignment
#pragma warning disable CA1416
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.

// ReSharper disable InconsistentNaming
#pragma warning disable CS8605 // Unboxing a possibly null value.
#pragma warning disable IDE0001

namespace NewDevice
{
    /// <summary>
    /// 海康相机类,一个相机实例化一次
    /// </summary>
    public class HKCamera
    {
        private object obj = new object();
        private object? _rawImage;
        private bool _isImageReady = false;
        private string? _name;
        private MyCamera.cbOutputExdelegate? ImageCallback;//回调
        private HKCameraInfo Camera;//相机绑定结构体
        private ImageType? _type;

        //所有的输入相机
        private MyCamera.MV_CC_DEVICE_INFO_LIST m_pDeviceList;

        /// <summary>
        /// 相机构造函数，传入对应的相机名以及图片类型
        /// </summary>
        /// <param name="CameraName"></param>
        /// <param name="imageType"></param>
        public HKCamera(string CameraName, ImageType imageType = ImageType.VMImageBaseDatas)
        {
            _name = CameraName;
            _type = imageType;
        }

        /// <summary>
        /// 打开相机,0成功，1失败
        /// </summary>
        public int Open()
        {
            Camera = new HKCameraInfo();
            //按照相机名称扫描相机
            int nRet = MyCamera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref m_pDeviceList);

            int m_nDevNum = (int)m_pDeviceList.nDeviceNum;

            for (int i = 0, j = 0; j < m_nDevNum; ++i, ++j)
            {
                MyCamera.MV_CC_DEVICE_INFO device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[j], typeof(MyCamera.MV_CC_DEVICE_INFO));
                if (device.nTLayerType == MyCamera.MV_USB_DEVICE)
                {
                    IntPtr buffer = Marshal.UnsafeAddrOfPinnedArrayElement(device.SpecialInfo.stUsb3VInfo, 0);

                    MyCamera.MV_USB3_DEVICE_INFO gigeInfo = (MyCamera.MV_USB3_DEVICE_INFO)Marshal.PtrToStructure(buffer, typeof(MyCamera.MV_USB3_DEVICE_INFO));

                    if (gigeInfo.chUserDefinedName == _name)
                    {
                        //如果对应相机存在
                        Camera.device = (MyCamera.MV_CC_DEVICE_INFO)Marshal.PtrToStructure(m_pDeviceList.pDeviceInfo[j], typeof(MyCamera.MV_CC_DEVICE_INFO));
                        Camera.Cam_Info = new MyCamera();
                        int ret1 = Camera.Cam_Info.MV_CC_CreateDevice_NET(ref Camera.device);
                        var ret2 = Camera.Cam_Info.MV_CC_OpenDevice_NET();
                        //设置触发模式和触发源
                        Camera.Cam_Info.MV_CC_SetTriggerMode_NET(1);
                        Camera.Cam_Info.MV_CC_SetTriggerSource_NET(7);
                        // ch:注册回调函数 | en:Register image callback
                        ImageCallback = new MyCamera.cbOutputExdelegate(ImageCallbackFunc);

                        int ret3 = Camera.Cam_Info.MV_CC_RegisterImageCallBackEx_NET(ImageCallback, IntPtr.Zero);
                        int ret4 = NecessaryOperBeforeGrab();

                        if (MyCamera.MV_OK != ret1 || MyCamera.MV_OK != ret2 || MyCamera.MV_OK != ret3 || MyCamera.MV_OK != ret4)
                        {
                            return 1;
                        }
                        int ret5 = Camera.Cam_Info.MV_CC_StartGrabbing_NET();
                        return ret5 == 0 ? 0 : 1;
                    }
                }
            }
            return 1;
        }

        /// <summary>
        /// 异步相机触发拍照,单次采集，堵塞方法
        /// </summary>
        public async Task<int> TriggerImage()
        {
            bool isSucsses = true;
            _isImageReady = false;
            Camera.Cam_Info.MV_CC_TriggerSoftwareExecute_NET();
            Stopwatch stopwatch = Stopwatch.StartNew();
            await Task.Run(async () =>
            {
                while (!_isImageReady)
                {
                    if (stopwatch.ElapsedMilliseconds > 5000)
                    {
                        isSucsses = false;
                        break;
                    }
                    await Task.Delay(100);
                }
            });

            return isSucsses ? 0 : 1;
        }

        /// <summary>
        /// 相机取图，外部销毁
        /// </summary>
        public object GetImage()
        {
            var image = _rawImage;
            _rawImage = null; // 内部放弃所有权
            return image;
        }

        /// <summary>
        /// 关闭相机
        /// </summary>
        public void Close()
        {
            Camera.Cam_Info.MV_CC_CloseDevice_NET();
            Camera.Cam_Info.MV_CC_DestroyDevice_NET();
        }

        /// <summary>
        /// 设置曝光
        /// </summary>
        public int SetExposure(float Expures)
        {
            return Camera.Cam_Info.MV_CC_SetExposureTime_NET(Expures);
        }

        /// <summary>
        /// 回调绑定方法
        /// </summary>
        /// <param name="pData"></param>
        /// <param name="stFrameInfo"></param>
        /// <param name="pUser"></param>
        private void ImageCallbackFunc(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX stFrameInfo, IntPtr pUser)
        {
            try
            {
                DateTime d11 = DateTime.Now;
                lock (obj)
                {
                    switch (_type)
                    {
                        case ImageType.Bitmap:
                            _rawImage = Inptr2Bitmap(pData, ref stFrameInfo, pUser);
                            break;

                        case ImageType.VMImageBaseDatas:
                            _rawImage = new VKCameraInfo(pData, stFrameInfo);
                            break;
                    }
                    _isImageReady = true;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private static ColorPalette grayPalette = null;
        private PixelFormat m_bitmapPixelFormat = PixelFormat.DontCare;
        private UInt32 m_nBufSizeForDriver = 0;
        private IntPtr m_BufForDriver = IntPtr.Zero;
        private IntPtr m_ConvertDstBuf = IntPtr.Zero;
        private UInt32 m_nConvertDstBufLen = 0;

        /// <summary>
        /// 用于灰度转化
        /// </summary>
        public static ColorPalette GrayPalette
        {
            get
            {
                if (grayPalette != null) return grayPalette;
                Bitmap bm = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
                grayPalette = bm.Palette;
                for (int i = 0; i < grayPalette.Entries.Length; i++)
                {
                    grayPalette.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
                }
                return grayPalette;
            }
        }

        /// <summary>
        /// 数据转bitmap格式
        /// </summary>
        /// <param name="pData"></param>
        /// <param name="stFrameInfo"></param>
        /// <param name="pUser"></param>
        /// <returns></returns>
        private Bitmap Inptr2Bitmap(IntPtr pData, ref MyCamera.MV_FRAME_OUT_INFO_EX stFrameInfo, IntPtr pUser)
        {
            Bitmap bmp = null;

            DateTime dStart = DateTime.Now;

            bmp = new Bitmap(stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nWidth * 1, PixelFormat.Format8bppIndexed, pData);
            // set palette back
            bmp.Palette = GrayPalette;

            Debug.WriteLine("HK-grayIMAGE CT:" + DateTime.Now.Subtract(dStart).TotalMilliseconds.ToString("0.000") + "ms");

            return bmp;
        }

        // ch:取图前的必要操作步骤 | en:Necessary operation before grab
        /// <summary>
        /// 检查相机
        /// </summary>
        /// <returns></returns>
        private Int32 NecessaryOperBeforeGrab()
        {
            // ch:取图像宽 | en:Get Iamge Width
            MyCamera.MVCC_INTVALUE_EX stWidth = new MyCamera.MVCC_INTVALUE_EX();
            int nRet = Camera.Cam_Info.MV_CC_GetIntValueEx_NET("Width", ref stWidth);
            if (MyCamera.MV_OK != nRet)
            {
                //ShowErrorMsg("Get Width Info Fail!", nRet);
                return nRet;
            }
            // ch:取图像高 | en:Get Iamge Height
            MyCamera.MVCC_INTVALUE_EX stHeight = new MyCamera.MVCC_INTVALUE_EX();
            nRet = Camera.Cam_Info.MV_CC_GetIntValueEx_NET("Height", ref stHeight);
            if (MyCamera.MV_OK != nRet)
            {
                //ShowErrorMsg("Get Height Info Fail!", nRet);
                return nRet;
            }
            // ch:取像素格式 | en:Get Pixel Format
            MyCamera.MVCC_ENUMVALUE stPixelFormat = new MyCamera.MVCC_ENUMVALUE();
            nRet = Camera.Cam_Info.MV_CC_GetEnumValue_NET("PixelFormat", ref stPixelFormat);
            if (MyCamera.MV_OK != nRet)
            {
                //ShowErrorMsg("Get Pixel Format Fail!", nRet);
                return nRet;
            }

            // ch:设置bitmap像素格式，申请相应大小内存 | en:Set Bitmap Pixel Format, alloc memory
            if ((Int32)MvGvspPixelType.PixelType_Gvsp_Undefined == stPixelFormat.nCurValue)
            {
                //ShowErrorMsg("Unknown Pixel Format!", MyCamera.MV_E_UNKNOW);
                return MyCamera.MV_E_UNKNOW;
            }
            else if (IsMono(stPixelFormat.nCurValue))
            {
                m_bitmapPixelFormat = PixelFormat.Format8bppIndexed;

                if (IntPtr.Zero != m_ConvertDstBuf)
                {
                    Marshal.Release(m_ConvertDstBuf);
                    m_ConvertDstBuf = IntPtr.Zero;
                }

                // Mono8为单通道
                m_nConvertDstBufLen = (UInt32)(stWidth.nCurValue * stHeight.nCurValue);
                m_ConvertDstBuf = Marshal.AllocHGlobal((Int32)m_nConvertDstBufLen);
                if (IntPtr.Zero == m_ConvertDstBuf)
                {
                    //ShowErrorMsg("Malloc Memory Fail!", MyCamera.MV_E_RESOURCE);
                    return MyCamera.MV_E_RESOURCE;
                }
            }
            else
            {
                m_bitmapPixelFormat = PixelFormat.Format24bppRgb;

                if (IntPtr.Zero != m_ConvertDstBuf)
                {
                    Marshal.FreeHGlobal(m_ConvertDstBuf);
                    m_ConvertDstBuf = IntPtr.Zero;
                }

                // RGB为三通道
                m_nConvertDstBufLen = (UInt32)(3 * stWidth.nCurValue * stHeight.nCurValue);
                m_ConvertDstBuf = Marshal.AllocHGlobal((Int32)m_nConvertDstBufLen);
                if (IntPtr.Zero == m_ConvertDstBuf)
                {
                    //ShowErrorMsg("Malloc Memory Fail!", MyCamera.MV_E_RESOURCE);
                    return MyCamera.MV_E_RESOURCE;
                }
            }

            // 确保释放保存了旧图像数据的bitmap实例，用新图像宽高等信息new一个新的bitmap实例
            if (null != _rawImage)
            {
                _rawImage = null;
            }
            //_rawImage = new Bitmap((Int32)stWidth.nCurValue, (Int32)stHeight.nCurValue, m_bitmapPixelFormat);

            //// ch:Mono8格式，设置为标准调色板 | en:Set Standard Palette in Mono8 Format
            //if (PixelFormat.Format8bppIndexed == m_bitmapPixelFormat)
            //{
            //    ColorPalette palette = _rawImage.Palette;
            //    for (int i = 0; i < palette.Entries.Length; i++)
            //    {
            //        palette.Entries[i] = Color.FromArgb(i, i, i);
            //    }
            //    _rawImage.Palette = palette;
            //}

            return MyCamera.MV_OK;
        }

        /// <summary>
        /// 灰度图判断
        /// </summary>
        /// <param name="enPixelType"></param>
        /// <returns></returns>
        private Boolean IsMono(UInt32 enPixelType)
        {
            switch (enPixelType)
            {
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono1p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono2p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono4p:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono8_Signed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono10_Packed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono12_Packed:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono14:
                case (UInt32)MyCamera.MvGvspPixelType.PixelType_Gvsp_Mono16:
                    return true;

                default:
                    return false;
            }
        }
    }

    /// <summary>
    /// 相机设备
    /// </summary>
    public struct HKCameraInfo
    {
        /// <summary>
        /// 输入设备
        /// </summary>
        public MV_CC_DEVICE_INFO device;

        /// <summary>
        /// 输入相机
        /// </summary>
        public MyCamera Cam_Info;
    }

    /// <summary>
    /// VM图片所需格式，需要在外部转化
    /// </summary>
    public class VKCameraInfo
    {
        /// <summary>
        /// INTPTR类型数据
        /// </summary>
        public IntPtr _pData;

        /// <summary>
        /// MV_FRAME_OUT_INFO_EX
        /// </summary>
        public MyCamera.MV_FRAME_OUT_INFO_EX _pFrameInfo;

        public VKCameraInfo(IntPtr pData, MyCamera.MV_FRAME_OUT_INFO_EX pFrameInfo)
        {
            _pData = pData;
            _pFrameInfo = pFrameInfo;
        }
    }

    /// <summary>
    /// 图片类型
    /// </summary>
    public enum ImageType
    {
        /// <summary>
        /// bitmap格式
        /// </summary>
        Bitmap,

        /// <summary>
        /// VM需要的格式
        /// </summary>
        VMImageBaseDatas
    }
}